import fs from 'fs';
import path from 'path';

// 命令行代码生成器
class GnindexGenerator {
  generateFiles: string[];
  generateDir: string;
  outputFile: string;

  constructor(generateDir: string, outputFile: string) {
    this.generateFiles = [];
    this.generateDir = generateDir;
    this.outputFile = outputFile;
  }

  // 递归扫描目录获取所有生成器文件
  scanGenerateFiles(dir: string, relativePath = '') {
    const entries = fs.readdirSync(dir, { withFileTypes: true });
    entries.forEach((entry) => {
       if (entry.isFile() && (entry.name.startsWith('generate-') || relativePath.startsWith('generate')) && entry.name.endsWith('.ts')) {
        const fullPath = path.posix.join(relativePath, entry.name);
        this.generateFiles.push(fullPath);
      } else if (entry.isDirectory()) {
        const subPath = path.posix.join(relativePath, entry.name);
        if (subPath.startsWith('generate')) {
          this.scanGenerateFiles(path.join(dir, entry.name), subPath);
        }
      }
    });
  }

  // 分析生成器文件内容
  analyzeGenerateFileContent(filePath: string) {
    const fullPath = path.join(this.generateDir, filePath);
    const content = fs.readFileSync(fullPath, 'utf8');

    // 提取命令名称（从文件名）
    const fileName = filePath.replace('.ts', '').replace('generate-', '').replace('generate/', '').replace('/', '-');
    let commandName = fileName;
    
    // 如果文件名以 'generate-' 开头，去掉这个前缀
    if (commandName.startsWith('generate-')) {
      commandName = commandName.substring('generate-'.length);
    }

    // 提取描述信息（从注释或导出的描述）
    const descriptionMatch = content.match(/\/\*\*\s*\n\s*\*\s*(.+?)\s*\n/);
    const description = descriptionMatch ? descriptionMatch[1] : `生成 ${commandName} 相关代码`;

    // 提取 JSDoc 参数描述
    const jsdocParamDescriptions: { [key: string]: string } = {};
    const jsdocMatch = content.match(/\/\*\*[\s\S]*?\*\//);
    if (jsdocMatch) {
      const jsdocContent = jsdocMatch[0];
      const paramMatches = jsdocContent.match(/@param\s+(\w+)\s+(.+)/g);
      if (paramMatches) {
        paramMatches.forEach(match => {
          const paramMatch = match.match(/@param\s+(\w+)\s+(.+)/);
          if (paramMatch) {
            jsdocParamDescriptions[paramMatch[1]] = paramMatch[2].trim();
          }
        });
      }
    }

    // 提取默认导出函数名作为别名
    let alias = '';
    
    // 匹配行首的 export default function functionName 的形式（忽略前面的空白字符）
    const namedFunctionMatch = content.match(/^[ \t]*export\s+default\s+function\s+(\w+)\s*\(/m);
    if (namedFunctionMatch) {
      alias = namedFunctionMatch[1];
    } else {
      // 匹配行首的 export default functionName 的形式（忽略前面的空白字符）
      const exportDefaultMatch = content.match(/^[ \t]*export\s+default\s+(\w+)/m);
      if (exportDefaultMatch) {
        alias = exportDefaultMatch[1];
      }
    }

    // 提取函数参数信息
    const exportFunctionMatch = content.match(/^[ \t]*export\s+default\s+function[^(]*\(([^)]*)\)/m);
    const parameters: Array<{name: string, flag: string, description: string, isPositional: boolean, hasDefault: boolean, type: string}> = [];
    
    if (exportFunctionMatch) {
      const paramString = exportFunctionMatch[1];
      // 匹配参数，包括可能的默认值和类型
      const paramMatches = paramString.match(/(\w+):\s*(string|boolean)(?:\s*=\s*[^,)]+)?/g);
      
      if (paramMatches) {
        paramMatches.forEach(param => {
          const paramName = param.split(':')[0].trim();
          const typeMatch = param.match(/:\s*(string|boolean)/);
          const paramType = typeMatch ? typeMatch[1] : 'string';
          const hasDefault = param.includes('=');
          const isPositional = paramType === 'string'; // 只有 string 类型作为位置参数
          
          parameters.push({
            name: paramName,
            flag: this.generateOptionFlag(paramName),
            description: this.generateOptionDescription(paramName, jsdocParamDescriptions),
            isPositional,
            hasDefault,
            type: paramType
          });
        });
      }
    }

    return {
      commandName,
      description,
      parameters,
      functionName: this.generateFunctionName(fileName),
      alias: alias || this.generateFunctionName(fileName), // 如果没有找到别名，使用生成的函数名
      importPath: './' + filePath.replace('.ts', '')
    };
  }

  // 生成选项标志
  generateOptionFlag(paramName: string) {
    // 将驼峰命名转换为短横线命名
    const kebabCase = paramName.replace(/([A-Z])/g, '-$1').toLowerCase();
    const shortFlag = paramName.charAt(0).toLowerCase();
    return `-${shortFlag}, --${kebabCase}`;
  }

  // 生成选项描述
  generateOptionDescription(paramName: string, jsdocDescriptions?: { [key: string]: string }) {
    // 优先使用 JSDoc 中的参数描述
    if (jsdocDescriptions && jsdocDescriptions[paramName]) {
      return jsdocDescriptions[paramName];
    }

    // 如果没有 JSDoc 描述，使用默认值
    return `${paramName} 参数`;
  }

  // 生成函数名
  generateFunctionName(fileName: string) {
    // 将 generate-xxx 转换为 generateXxx
    return fileName.replace(/generate-(\w)/, (match, firstChar) => 
      'generate' + firstChar.toUpperCase()
    ).replace(/-(\w)/g, (match, char) => char.toUpperCase());
  }

  // 生成命令行代码
  generateCommandCode() {
    this.scanGenerateFiles(this.generateDir);

    const commands = this.generateFiles
      .map((file) => this.analyzeGenerateFileContent(file))
      .sort((a, b) => a.commandName.localeCompare(b.commandName));

    // 生成命令注册代码
    const commandRegistrations = commands.map(cmd => {
      // 分离位置参数和选项参数
      const positionalParams = cmd.parameters.filter(param => param.isPositional);
      const optionParams = cmd.parameters.filter(param => !param.isPositional);
      
      // 生成位置参数
      const argumentsCode = positionalParams.map(param => {
        const argSyntax = param.hasDefault ? `[${param.name}]` : `<${param.name}>`;
        return `  .argument('${argSyntax}', '${param.description}')`;
      }).join('\n');
      
      // 生成选项参数（只为 boolean 类型生成）
      const booleanOptions = cmd.parameters.filter(param => param.type === 'boolean');
      const options = booleanOptions.map(param => 
        `  .option('${param.flag}', '${param.description}')`
      ).join('\n');

      // 生成 action 处理函数的参数
      const positionalParamNames = positionalParams.map(param => param.name);
      const allParamNames = cmd.parameters.map(param => param.name);
      
      // 构建 action 函数的参数和逻辑
      let actionSignature: string;
      let actionBody: string;
      
      if (positionalParams.length > 0) {
        // 有位置参数的情况：列出所有位置参数名 + options
        const paramList = [...positionalParamNames, 'options'].join(', ');
        actionSignature = `(${paramList})`;
        
        // 生成函数调用的参数
        const functionCallParams = allParamNames.map(param => {
          const paramObj = cmd.parameters.find(p => p.name === param);
          if (paramObj?.isPositional) {
            // 位置参数：string 类型，使用 || options.param 的形式（虽然 string 参数不再生成 options）
            return param;
          } else {
            // 选项参数：boolean 类型，直接从 options 获取
            return `options.${param}`;
          }
        });
        
        actionBody = `    import('${cmd.importPath}').then(module => {
      module.default(${functionCallParams.join(', ')});
    });`;
      } else {
        // 没有位置参数的情况，只有 boolean 选项
        if (booleanOptions.length > 0) {
          actionSignature = `(options)`;
          const functionCallParams = allParamNames.map(param => `options.${param}`);
          actionBody = `    import('${cmd.importPath}').then(module => {
      module.default(${functionCallParams.join(', ')});
    });`;
        } else {
          // 没有任何参数
          actionSignature = `()`;
          actionBody = `    import('${cmd.importPath}').then(module => {
      module.default();
    });`;
        }
      }

      return `program
  .command('${cmd.commandName}')
  .alias('${cmd.alias}')
  .description('${cmd.description}')${argumentsCode ? '\n' + argumentsCode : ''}
${options}
  .action(${actionSignature} => {
${actionBody}
  });`;
    }).join('\n\n');

    // 完整的代码模板
    const code = `import { Command } from 'commander';

const program = new Command()

${commandRegistrations}

program.parse(process.argv);`;

    return code;
  }

  // 保存生成的代码到文件
  generate() {
    try {
      const code = this.generateCommandCode();
      fs.writeFileSync(this.outputFile, code, 'utf8');
      console.log('✅ 命令行代码已成功生成到:', this.outputFile);
      console.log('📝 共生成', this.generateFiles.length, '个命令');

      // 显示生成的命令列表
      console.log('\n📋 生成的命令列表:');
      this.generateFiles.forEach((file) => {
        const cmd = this.analyzeGenerateFileContent(file);
        const positionalArgs = cmd.parameters.filter(p => p.isPositional).map(p => {
          const syntax = p.hasDefault ? `[${p.name}]` : `<${p.name}>`;
          return syntax;
        }).join(' ');
        const booleanOptions = cmd.parameters.filter(p => p.type === 'boolean').map(p => `--${p.flag.split('--')[1]}`).join(' ');
        const paramStr = [positionalArgs, booleanOptions].filter(Boolean).join(' ');
        console.log(`  ${cmd.commandName.padEnd(15)} (${cmd.alias}) ${cmd.description} ${paramStr ? `(${paramStr})` : ''}`);
      });
    } catch (error: any) {
      console.error('❌ 生成命令行代码时发生错误:', error.message);
    }
  }
}

/**
 * 生成 Generate 指令的注册代码
 * @param dir 需要扫描的 Generate 目录
 * @param output 输出的文件路径
 */
export default function gni(dir: string, output: string) {
  const generator = new GnindexGenerator(dir, output);
  generator.generate();
}
